04. Create Store: Getting and Listening

In this section, we'll be building the store. If you remember from the previous section, the store has the following information:

  • the state tree
  • a way to get the state tree
  • a way to listen and respond to the state changing
  • a way to update the state

The Store contains the state tree and provides ways to interact with the state tree.

The Store contains the state tree and provides ways to interact with the state tree.

So this is what we're going to do in this lesson - we're going to actually create the store code ourselves, from scratch.

In the following video, we'll start with a blank index.js file and create a factory function that creates store objects. Then we'll have the store keep track of the state, and we'll write the method to get the state from the store.

Pop open your code editor, and let's get started!

Getting The State

In this screencast, we started building out the createStore function. Currently, this factory function:

  • takes in no arguments
  • sets up a local (private) variable to hold the state
  • sets up a getState() function
  • returns an object that publicly exposes the getState() function

Let's take a look at the getState() function

Quiz: getState()

Thinking about the code we just wrote, what does the getState() function do?

SOLUTION: It returns the existing state variable.

Our list of things we need to build for the store is shrinking:

  • the state tree
  • a way to get the state tree
  • a way to listen and respond to the state changing
  • a way to update the state

Our next task on the list is to make a way to listen for changes to the state.

Listening To Changes

Unsubscribing The Listener

Keep in mind that

const subscribe = (listener) => {
    listeners.push(listener)
    return () => {
      listeners = listeners.filter((l) => l !== listener)
    }
  }

is equivalent to the following ES5:

var subscribe = function subscribe(listener) {
  listeners.push(listener);
  return function () {
    listeners = listeners.filter(function (l) {
      return l !== listener;
    });
  };
};

subscribe()

Which of the following are true about store.subscribe()?

SOLUTION:
  • It is a function.
  • When called, it is passed a single function.
  • It returns a function.

Updating The State

We've got our first rule!

Only an event can change the state of the store.

Ok…well, without knowing what an "event" is, this rule is less than helpful :-\ Fear not, because we're going to look at what events are in this video:

Intro To Actions

When an event takes place in a Redux application, we use a plain JavaScript object to keep track of what the specific event was. This object is called an Action.

Let's take another look at an Action:

{
  type: "ADD_PRODUCT_TO_CART"
}

As you can see, an Action is clearly just a plain JavaScript object. What makes this plain JavaScript object special in Redux, is that every Action must have a type property. The purpose of the type property is to let our app (Redux) know exactly what event just took place. This Action tells us that a product was added to the cart. That's incredibly descriptive and quite helpful, isn't it?

Now, since an Action is just a regular object, we can include extra data about the event that took place:

{
  type: "ADD_PRODUCT_TO_CART",
  productId: 17
}

In this Action, we're including the productId field. Now we know exactly which product was added to the store!

One more note to keep in mind as you build your Action objects: it's better practice to pass as little data as possible in each action. That is, prefer passing the index or ID of a product rather than the entire product object itself.

Action Creators are functions that create/return action objects. For example:

const addItem = item => ({
  type: ADD_ITEM,
  item
});

or in ES5:

var addItem = function addItem(item) {
  return {
    type: ADD_ITEM,
    item: item
  };
};

Type is Required

Is it true that every Action must have a type property?

SOLUTION: Yes

Additional Fields

Can an Action have three or more fields?

SOLUTION: Yes

Quiz: Valid Action?

Consider the following five options for the next quiz:

// A

const receivePost = post => ({
  type: RECEIVE_POST,
  post
});
// B

const receivePost = post => ({
  type: RECEIVE_POST,
  post: post
}); 
// C

const clearErrors = {
  type: CLEAR_ERRORS
};
// D

const addSeven = {
  type: 'ADD_NUMBER',
  number: 7
};
// E

const removeComments = {
  comments: null
};

Quiz: Valid Action?

Which of the above options are valid actions?

SOLUTION:
  • C
  • D

Summary

In this section, we started creating our store by building out a createStore() function. So far, this function keeps track of the state, and provides a method to get the state and one to keep track of listener functions that will be run whenever the state changes.

In the next section, we'll add a method to handle updating the state.